#pragma once
#include<atomic>
#include<functional>

template<class T>
class shared_ptr
{
public:
	shared_ptr(T* ptr)
		:_ptr(ptr)
		, _pcnt(new std::atomic<int>(1))
	{
	}

	template<class K>
	shared_ptr(T* ptr,K del)
		:_ptr(ptr)
		, _pcnt(new std::atomic<int>(1))
		,_del(del)
	{
	}

	shared_ptr(const shared_ptr<T>& p)
		:_ptr(p._ptr)
		,_pcnt(p._pcnt)
	{
		(*_pcnt)++;
	}

	shared_ptr<T> & operator=(const shared_ptr<T>& p)
	{
		if (_ptr != p._ptr)
		{
			this->release();
			_ptr = p._ptr;
			_pcnt = p._pcnt;
			(*_pcnt)++;
		}
	}

	void release()
	{
		if (--(*_pcnt) == 0)
		{
			_del(_ptr);
			delete _pcnt;
		}
	}

	int use_count()
	{
		return *_pcnt;
	}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

	~shared_ptr()
	{
		release();
	}
private:
	T* _ptr;
	std::atomic<int>* _pcnt;
	std::function<void(T*)> _del = [](T* ptr) {delete ptr; };
};

